package com.sjgl.esdn.service.impl;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.sjgl.esdn.constant.FileConstantsESDN;
import com.sjgl.esdn.domain.entity.Boxroom;
import com.sjgl.esdn.domain.entity.TempBlog;
import com.sjgl.esdn.domain.entity.File;
import com.sjgl.esdn.domain.entity.uc.UCMessage;
import com.sjgl.esdn.domain.entity.vo.HotFileVo;
import com.sjgl.esdn.mapper.FileMapper;
import com.sjgl.esdn.mapper.UCMessageMapper;
import com.sjgl.esdn.mapper.UserMapper;
import com.sjgl.esdn.search.domain.MyFile;
import com.sjgl.esdn.service.BoxroomService;
import com.sjgl.esdn.service.DeptService;
import com.sjgl.esdn.service.FileService;
import com.sjgl.esdn.service.UserService;
import com.sjgl.esdn.utils.DateUtilsESDN;
import com.sjgl.esdn.utils.ImageUtilsESDN;
import com.sjgl.esdn.utils.TextUtilESDN;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.*;

import static com.sjgl.esdn.utils.TextUtilESDN.isFileAllowed;


/**
 * 文件 服务层处理
 *
 * @author Administrator
 * @date 2022/08/05
 */
@Service
public class FileServiceImpl implements FileService {
    private static final Logger log = LoggerFactory.getLogger(FileServiceImpl.class);
    @Resource
    private RestHighLevelClient esclient;

    private static final String ESDN_INDEX = "esdn2";

    //可转pdf的后缀集合
    static Set<String> set = new HashSet<>();

    static {
        set.add("doc");
        set.add("docx");
        set.add("xls");
        set.add("xlsx");
        set.add("ppt");
        set.add("pptx");
    }

    @Autowired
    FileMapper fileMapper;

    @Autowired
    UserMapper userMapper;

    @Autowired
    UserService userService;

    @Autowired
    DeptService deptService;

    @Autowired
    BoxroomService boxroomService;

    @Autowired
    private UCMessageMapper ucMessageMapper;

    @Override
    public int insertFile(File file, List<Long> deptIds, List<Long> labelIds) {
        //文件信息插入
        int rows = fileMapper.insertFile(file);
        if (rows == 0) {
            return rows;
        }

        //文件、部门关联
        if (file.getFileType() == 1) {
            fileMapper.insertFileDept(file.getFileId(), -1L);
        } else if (file.getFileType() == 2&&deptIds!=null) {
            for (Long deptId : deptIds) {
                fileMapper.insertFileDept(file.getFileId(), deptId);
            }
        }

        //文件、标签关联
        if(labelIds!=null){
            for (Long labelId : labelIds) {
                fileMapper.insertFileLabel(file.getFileId(),labelId);
            }
        }

        //文件、专栏关联
        if(file.getColumnId()!=null){
            fileMapper.insertFileColumn(file.getFileId(),file.getColumnId());
        }

        //若之前为博客草稿，将其删除
        if(file.getTempBlogId()!=null){
            fileMapper.deleteTempBlog(file.getTempBlogId());
        }

        //返回
        return rows;
    }

    @Override
    public int insertFile(File file, List<Long> deptIds) {
        return insertFile(file,deptIds,null);
    }

    @Override
    public void insertFileES(File file) throws IOException {
        File esFile = selectFileById(file.getFileId());

        MyFile myFile = new MyFile();
        myFile.setId(esFile.getFileId().toString());
        myFile.setFileName(esFile.getFileName());
        myFile.setFileIntro(esFile.getFileIntro());

        //路径
        String path = selectFilePathById(file.getFileId());

        if (isFileAllowed(esFile.getFileSuffix())) {
            try {
                String content = getStringFromFile(file);
                myFile.setFileContent(content);
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            myFile.setFileContent(null);
        }

        myFile.setFileSuffix(esFile.getFileSuffix());
        myFile.setFileType(esFile.getFileType());
        myFile.setDownloadNum(esFile.getDownloadNum().intValue());
        myFile.setTitleCompletion(esFile.getFileName());
        myFile.setCreateTime(esFile.getCreateTime());
        myFile.setPreviewUrl(selectPreviewPath(file.getFileId()));

        System.out.println(myFile);//test

        //插入数据
        IndexRequest indexRequest = new IndexRequest();
        //需要插入的数据  index|索引  id|唯一标识
        indexRequest.index(ESDN_INDEX).id(esFile.getFileId().toString());
        // 向es插入数据，必须将数据转换为json  jackson
        ObjectMapper mapper = new ObjectMapper();
        String myFilejson = null;//对象转str
        try {
            myFilejson = mapper.writeValueAsString(myFile);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        indexRequest.source(myFilejson, XContentType.JSON);//index为user，id1020的数据
        IndexResponse index = null;
        try {
            index = esclient.index(indexRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }

        ///关闭连接
/*        try {
            esclient.close();
        } catch (IOException e) {
            e.printStackTrace();
        }*/
    }

    @Override
    public int getSplitPoint(String fileName) {
        return fileName.lastIndexOf('.');
    }

    @Override
    public String selectFolder(String fileSuffix) {
        String location = fileMapper.selectFolder(fileSuffix);
        if (location == null) {
            return null;
        } else {
            return FileConstantsESDN.WindowsFilePosition + location;
        }
    }

    @Override
    public String selectFilePathById(Long fileId) {
        File file=selectFileById(fileId);
        return selectFolder(file.getFileSuffix()) + DateUtilsESDN.getYYYYMMByDate(file.getCreateTime()) + "\\" + file.getFileId() + "." + file.getFileSuffix();
    }

    @Override
    public String selectPdfPathById(Long fileId) {
        File file=selectFileById(fileId);
        return selectFolder("pdf") + DateUtilsESDN.getYYYYMMByDate(file.getCreateTime()) + "\\" + file.getFileId() + ".pdf";
    }

    @Override
    public int deleteFile(Long fileId, Long userId, String reason) {
        //传入参数出错
        if (userMapper.checkIdUnique(userId) == 0 || fileMapper.checkFileUnique(fileId) == 0) {
            return -1;
        }
        //无权限
        if (!canUserUpdateFile(userId, fileId)) {
            return 0;
        }

        //ES操作
        deleteFileES(fileId);

        //删除文件
        return fileMapper.deleteFile(fileId, userId, reason);
    }

    @Override
    public void deleteFileES(Long fileId) {
        //插入数据,再前面我们都是创建indices然后去创建跟索引库相关的
        UpdateRequest request = new UpdateRequest();
        //在修改数据的时候我们就不叫index，应该是update
        // 修改数据我们是对文档的数据进行修改
        request.index(ESDN_INDEX).id(fileId.toString()); // 表示对哪个索引库进行修改对那条数据进行修改
        // doc 表示文档数据
        request.doc(XContentType.JSON, "fileType", "-1");
        UpdateResponse response = null;
        try {
            response = esclient.update(request, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }
/*        try {
            esclient.close();
        } catch (IOException e) {
            e.printStackTrace();
        }*/
    }

    @Override
    public int downloadFile(Long fileId, Long userId) {
        //传入参数出错
        if (userMapper.checkIdUnique(userId) == 0 || fileMapper.checkFileUnique(fileId) == 0) {
            return -1;
        }
        //无权限
        if (!canUserLookFile(userId, fileId)) {
            return 0;
        }
        //文件下载表处理
        if (hasUserDownloadFile(userId, fileId)) {
            fileMapper.downloadFile2(fileId, userId);
        } else {
            fileMapper.downloadFile1(fileId, userId);
        }

        //ES处理
        try {
            downloadFileES(fileId);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        //记录下载log_user
        File file = selectFileById(fileId);
        ucMessageMapper.insertMessage(new UCMessage(null,51L,userId,file.getCreateBy(),null,file.getFileId(),file.getIsBlog(),null));

        //下载量增加
        return fileMapper.downloadNumAdd(fileId);
    }

    @Override
    public void downloadFileES(Long fileId) throws IOException {
        UpdateRequest request = new UpdateRequest();
        //在修改数据的时候我们就不叫index，应该是update
        // 修改数据我们是对文档的数据进行修改
        request.index(ESDN_INDEX).id(fileId.toString()); // 表示对哪个索引库进行修改对那条数据进行修改
        // doc 表示文档数据
        File file = selectFileById(fileId);
        request.doc(XContentType.JSON, "downloadNum", file.getDownloadNum() + 1);
        UpdateResponse response = null;
        try {
            response = esclient.update(request, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }
/*        try {
            esclient.close();
        } catch (IOException e) {
            e.printStackTrace();
        }*/
    }

    @Override
    public int updateFile(File file, List<Long> deptIds) {
        //传入参数出错
        if (userMapper.checkIdUnique(file.getUpdateBy()) == 0 || fileMapper.checkFileUnique(file.getFileId()) == 0) {
            return -1;
        }
        //无权限
        if (!canUserUpdateFile(file.getUpdateBy(), file.getFileId())) {
            return 0;
        }

        //修改文件信息
        int rows = fileMapper.updateFile(file);
        //文件、部门取消关联
        fileMapper.deleteFileDept(file.getFileId());
        //文件、部门重新关联
        if (file.getFileType() == 1) {
            fileMapper.insertFileDept(file.getFileId(), -1L);
        } else if (file.getFileType() == 2) {
            for (Long deptId : deptIds) {
                fileMapper.insertFileDept(file.getFileId(), deptId);
            }
        }

        //ES操作

        return rows;
    }

    @Override
    public boolean canUserUpdateFile(Long userId, Long fileId) {
        //if文件上传者是用户|（用户是部门管理员&文件上传者所属于该部门）|用户是管理员 return true
        Long createBy = fileMapper.getCreateByByFileId(fileId);
        if (Objects.equals(createBy, userId)) {
            return true;
        }
        Integer userType = userMapper.getUserType(userId);
        Long deptId1 = userMapper.getDeptId(createBy);
        Long deptId2 = userMapper.getDeptId(userId);
        if (userType == 2 && Objects.equals(deptId1, deptId2)) {
            return true;
        }
        if (userType == 3) {
            return true;
        }
        return false;
    }

    @Override
    public boolean canUserLookFile(Long userId, Long fileId) {
        //if文件部门id=-1|（用户是员工/部门管理员&文件部门id包含用户部门id）|用户是管理员 return true
        List<Long> deptIdList = fileMapper.getDeptIdList(fileId);
        if (deptIdList.contains(-1L)) {
            return true;
        }
        Integer userType = userMapper.getUserType(userId);
        Long deptId = userMapper.getDeptId(userId);
        if (userType == 1 && deptIdList.contains(deptId)) {
            return true;
        }
        if (userType > 1 && deptIdList.contains(deptId)) {
            return true;
        }
        if (userType == 3) {
            return true;
        }
        return false;
    }

    @Override
    public boolean hasUserDownloadFile(Long userId, Long fileId) {
        if (fileMapper.hasUserDownloadFile(userId, fileId) > 0) {
            return true;
        }
        return false;
    }

    @Override
    public boolean hasUserBrowseFile(Long userId, Long fileId) {
        if (fileMapper.hasUserBrowseFile(userId, fileId) > 0) {
            return true;
        }
        return false;
    }

    @Override
    public boolean canFileToPdf(String suffix) {
        return set.contains(suffix);
    }

    @Override
    public File selectFileById(Long fileId){
        return fileMapper.selectFileById(fileId);
    }

    @Override
    public File lookFile(Long fileId, Long userId) throws IOException {
        //浏览量增加
        fileMapper.browseNumAdd(fileId);
        //关系表增加/修改
        if (hasUserBrowseFile(userId, fileId)) {
            fileMapper.browseFile2(fileId, userId);
        } else {
            fileMapper.browseFile1(fileId, userId);
        }

        return selectFileById(fileId);
    }

    @Override
    public List<File> selectFileListByIdList(List<Long> fileIdList) throws IOException {
        List<File> fileList = new ArrayList<>();
        for (Long fileId : fileIdList) {
            fileList.add(selectFileById(fileId));
        }
        return fileList;
    }

    @Override
    public List<File> getUploadFileListByUserId(Long userId) throws IOException {
        //上传文件列表
        List<File> fileList = fileMapper.getUploadFileListByUserId(userId);
        //对每个文件加入可见部门列表,预览图
        for (File file : fileList) {
            List<Long> deptIdList = fileMapper.getDeptIdList(file.getFileId());
            List<String> deptNameList = deptService.getDeptNameListByIdList(deptIdList);
            file.setDeptNameList(deptNameList);
        }
        return fileList;
    }

    @Override
    public BufferedImage getPreview(Long fileId) throws IOException {
        return ImageIO.read(new java.io.File(selectPreviewPath(fileId)));
    }

    @Override
    public String selectPreviewPath(Long fileId){
        File file=selectFileById(fileId);
        String path;
        //若文件本身是图片，预览图位置即本身，代码待改进
        if("jpg".equals(file.getFileSuffix())||"png".equals(file.getFileSuffix())){
            path = selectFilePathById(fileId);
        }else{
            path = selectFolder("preview") + DateUtilsESDN.getYYYYMMByDate(file.getCreateTime()) + "\\" + file.getFileId() + ".jpg";
        }
        if (!new java.io.File(path).exists()) {
            return selectFolder("preview") + "0.jpg";
        }
        return path;
    }

    @Override
    public String getStringFromFile(com.sjgl.esdn.domain.entity.File file) throws Exception {

        String fileSuffix = file.getFileSuffix().toLowerCase();
        //判断后缀
        if (!TextUtilESDN.isFileAllowed(fileSuffix)) {
            return null;
        }
        String path = selectFilePathById(file.getFileId());

        String string = "";
        if (fileSuffix.equals("txt")) {
            string = TextUtilESDN.getTextFromTxt(path);
        } else if (fileSuffix.equals("doc")) {
            string = TextUtilESDN.getTextFromDoc(path);
        } else if (fileSuffix.equals("docx")) {
            string = TextUtilESDN.getTextFromDocx(path);
        } else if (fileSuffix.equals("pdf")) {
            string = TextUtilESDN.getTextFromPDF(path);
        } else if (fileSuffix.equals("ppt")) {
            string = TextUtilESDN.getTextFromPPT(path);
        } else if (fileSuffix.equals("pptx")) {
            string = TextUtilESDN.getTextFromPPTX(path);
        } else if (fileSuffix.equals("xls")) {
            string = TextUtilESDN.getTextFromXLS(path);
        } else if (fileSuffix.equals("xlsx")) {
            string = TextUtilESDN.getTextFromXLSX(path);
        }else {
            string = "当前不支持此类型";
        }
        return string;
    }

    @Override
    public Boolean isFileExist(Long fileId) {
        return fileMapper.checkFileUnique(fileId) != 0;
    }

    @Override
    public Boolean isUserLikeFile(Long userId, Long fileId) {
        return fileMapper.isUserLikeFile(userId, fileId) == 1;
    }

    @Override
    public Boolean isUserCollectionFile(Long userId, Long fileId) {
        //对用户的每个收藏夹进行查找，找到文件即返回true，否则返回false
        List<Long> boxroomIdList = boxroomService.selectBoxroomIdListByUserId(userId);
        for (Long boxroomId : boxroomIdList) {
            if (boxroomService.isBoxroomAndFileExist(boxroomId, fileId)) {
                return true;
            }
        }
        return false;
    }

    @Override
    public int deleteUserLikeFile(Long userId, Long fileId) {
        fileMapper.likeNumDec(fileId);
        return fileMapper.deleteUserLikeFile(userId, fileId);
    }

    @Override
    public int addUserLikeFile(Long userId, Long fileId) {
        fileMapper.likeNumAdd(fileId);
        //记录点赞log_user
        File file = selectFileById(fileId);
        ucMessageMapper.insertMessage(new UCMessage(null,20L,userId,file.getCreateBy(),null,file.getFileId(),file.getIsBlog(),null));

        return fileMapper.addUserLikeFile(userId, fileId);
    }

    @Override
    public int saveTempBlog(TempBlog tempBlog) {
        return tempBlog.getTempBlogId()==null?fileMapper.saveTempBlog(tempBlog):fileMapper.updateTempBlog(tempBlog);
    }

    @Override
    public List<TempBlog> getTempBlogList(Long userId) {
        return fileMapper.getTempBlogList(userId);
    }

    @Override
    public List<HotFileVo> getHotFileList(Long userId,Long limit) {
        //未处理过的热点文件
        List<HotFileVo> hotFileVoList1 = fileMapper.getHotFileList1(limit);
        //最终返回的热点文件
        List<HotFileVo> hotFileVoList2 = new ArrayList<>();

        //权限判断
        for (HotFileVo hotFileVo : hotFileVoList1) {
            if(canUserLookFile(userId, hotFileVo.getFileId())){
                //构造完整的热点文件
                HotFileVo t=fileMapper.getHotFileById(hotFileVo.getFileId());
                t.setFileJPG(ImageUtilsESDN.fileToBase64(selectPreviewPath(t.getFileId())));
                t.setUserJPG(userService.getUserAvatar(t.getUserId()));
                t.setUserName(userMapper.getUserName(t.getUserId()));
                t.setHotNum(hotFileVo.getHotNum());

                hotFileVoList2.add(t);
                if(--limit<=0){
                    break;
                }
            }
        }

        return hotFileVoList2;
    }

    @Override
    public List<File> getRecentDownloadFileList(Long userId,Long days,Long limit) {
        List<File> fileList=fileMapper.getRecentDownloadFileList(days);
        List<File> fileList1=new ArrayList<>();

        for (File file : fileList) {
            if(!canUserLookFile(userId, file.getFileId())){
                continue;
            }
            File t=selectFileById(file.getFileId());
            t.setDownloadNum(file.getDownloadNum());
            fileList1.add(t);
            if(--limit<=0){
                break;
            }
        }
        return fileList1;
    }

}
